using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

using SdlDotNet.Graphics;
using SdlDotNet.Graphics.Sprites;
using System.Drawing;
using SdlDotNet.Core;
using SdlDotNet.Input;
using SnakeCharp.Game;

namespace SnakeCharp.Entity
{
    /// <summary>
    /// Represents the actual player of the game
    /// </summary>
    public class Snake : AnimatedSprite
    {
        private SnakeTail tail;
        private SnakeState state;
        private float speed;

        //Used to calculate the precise position
        private float floatX,floatY;

        public Snake()
        {
            //Setup the start location
            //This should maybe come from params from the constructor?
            this.floatX = Configurations.ScreenWidth / 2;
            this.floatY = Configurations.ScreenHeight / 2;
            this.X = (int)this.floatX;
            this.Y = (int)this.floatY;
            this.speed = 4.0F;
            this.tail = new SnakeTail(new Point(this.X, this.Y), this.speed);
            this.state = SnakeState.Up;

            SetupAnimations("Snake_Head.png");
            this.Animate = true;
        }

        /// <summary>
        /// Renders the specified interpolation.
        /// </summary>
        /// <param name="interpolation">The interpolation.</param>
        /// <returns></returns>
        public void Render(float interpolation, Surface destinationSurface)
        {
            switch (state)
            {
                case SnakeState.Up:
                    this.Y = (int)(this.floatY - (speed * interpolation)); 
                    break;
                case SnakeState.Down:
                    this.Y = (int)(this.floatY + (speed * interpolation)); 
                    break;
                case SnakeState.Left:
                    this.X = (int)(this.floatX - (speed * interpolation));
                    break;
                case SnakeState.Right:
                    this.X = (int)(this.floatX + (speed * interpolation));
                    break;
                case SnakeState.Dead:
                    //Do nothing so the Snake will stop
                    break;
                default:
                    break;
            }

            //Render Tail
            this.tail.Render(interpolation, destinationSurface);

            //Render Snake
            destinationSurface.Blit(this);
        }

        public void Update(Controller input, TickEventArgs e)
        {
            //Update the SnakeState from the user inputs
            UpdateState(input);

            //Update the X and Y from the SnakeState
            UpdatePosition();

            //Update the X and Y from the size of the screen
            UpdateBounds();

            //Update tail
            tail.Update(this.Center, this.speed);
        }

        /// <summary>
        /// Updates the position.
        /// </summary>
        private void UpdatePosition()
        {
            switch (state)
            {
                case SnakeState.Up:
                    this.floatY -= speed;
                    break;
                case SnakeState.Down:
                    this.floatY += speed;
                    break;
                case SnakeState.Left:
                    this.floatX -= speed;
                    break;
                case SnakeState.Right:
                    this.floatX += speed;
                    break;
                case SnakeState.Dead:
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// Updates accordingly to the snakes bounds.
        /// Makes the Snake stay inside the screen.
        /// </summary>
        private void UpdateBounds()
        {
            //X axis
            if (this.floatX < 0 - this.Width)
                this.floatX = Screen.Width;
            else if (this.floatX > Screen.Width)
                this.floatX = 0 - (this.Width);

            //Y axis
            else if (this.floatY < 0 - (this.Height))
                this.floatY = Screen.Height;
            else if (this.floatY > Screen.Height)
                this.floatY = 0 - (this.Height);
        }

        private void UpdateState(Controller input)
        {
            // Updates the state of the snake and prevents the snake from moving in the direction it came from
            if (input.CheckKey(Key.RightArrow) && state != SnakeState.Left)
            { state = SnakeState.Right; }
            else if (input.CheckKey(Key.LeftArrow) && state != SnakeState.Right)
            { state = SnakeState.Left; }
            else if (input.CheckKey(Key.UpArrow) && state != SnakeState.Down)
            { state = SnakeState.Up; }
            else if (input.CheckKey(Key.DownArrow) && state != SnakeState.Up)
            { state = SnakeState.Down; }
        }

        private void SetupAnimations(string name)
        {
            //Load the Sprite 
            string spritedir = Configurations.ImagePath + name;

            //Load the Image to a Surface
            Surface image = new Surface(spritedir);

            //Load the Surface to a Sufrace Collection
            SurfaceCollection item = new SurfaceCollection();
            for (int i = 0; i < (image.Height / 50); i++)
            {
                item.Add(image, new Size(50, 50), i);
            }

            #region SurfaceCollections

            //Adds the Default Animation
            SurfaceCollection defaultCollection = new SurfaceCollection();

            for (int i = 0; i < 2; i++)
            {
                defaultCollection.Add(item[i], new Size(50, 50));
            }


            #endregion

            #region AnimationCollections
            //Adds the Default Animation
            AnimationCollection defaultAnimation = new AnimationCollection();            
            defaultAnimation.Add(defaultCollection, 500); 


            this.Animations.Add("Default", defaultAnimation);

            #endregion

            this.CurrentAnimation = "Default";
        }

        #region Properties
        public SnakeTail Tail
        {
            get { return tail; }
        } 
        #endregion
    }
}
